import hashlib
import datetime as date
from flask import Flask
from flask import request, jsonify,render_template
from uuid import uuid4


# 定义区块结构
class Block:
    def __init__(self, index, timestamp, transactions, previous_proof, previous_hash):
        # 一个区块包含的基本元素（索引，时间戳，工作量证明，交易信息，前一个区块的哈希值）
        self.index = index
        self.timestamp = timestamp
        self.transactions = transactions
        self.previous_hash = previous_hash
        self.proof = self.proof_of_work(previous_proof)
        self.hash = self.hash_block()

    # 工作量证明
    def proof_of_work(self, previous_proof):
        # index为0表明为创世区块，工作量证明设置为0
        if self.index == 0:
            incrementor = 0
            return incrementor
        # 非创世区块工作量证明计算
        if previous_proof == 0:  # 避免除0出错的问题
            previous_proof = 1
        incrementor = previous_proof + 1
        while not (incrementor % 9 == 0 and incrementor % previous_proof == 0):
            incrementor += 1
        return incrementor

    # 生成当前区块的哈希值
    def hash_block(self):
        sha = hashlib.sha256()
        sha.update((str(self.index) + str(self.timestamp) + str(self.transactions) + str(self.previous_hash) + str(
            self.proof)).encode('utf-8'))
        return sha.hexdigest()


# 定义创世区块生成函数
def create_genesis_block():
    # index为0，时间为生成该区块的时间，工作量证明为0，交易信息为空，哈希值为0
    return Block(0, date.datetime.now(), [], 0, "0")


# 生成一个新的区块并添加到区块链中
def add_block_to_blockchain(blockchain, new_transactions):
    # 新区块各个要素的值
    last_block = blockchain[-1]
    this_index = last_block.index + 1
    this_timestamp = date.datetime.now()
    current_transactions = new_transactions
    previous_proof = last_block.proof
    previous_hash = last_block.hash
    # 生成新块并添加到链
    blockchain.append(Block(this_index, this_timestamp, current_transactions, previous_proof, previous_hash))
    return blockchain


# 实例化节点（创建一个节点）
node = Flask(__name__)
# 为该节点生成一个全局唯一的地址（为节点创建一个随机的名字）
node_identifier = str(uuid4()).replace('-', '')


# 查看运行信息
@node.route('/')
def run_message():
    return 'Hello! Runing on http://127.0.0.1:5000/'


# 挖矿
@node.route('/mine', methods=['GET'])
def mine():
    # 获取交易信息的一个拷贝（非引用），避免“广播”错误，否则仅发送交易信息，就直接导致原有区块交易信息的改变
    # 只有在挖矿的时候，才会将new_transaction信息加入到新块中
    new_transactions = this_node_transactions.copy()
    add_block_to_blockchain(blockchain, new_transactions)
    mined_block = blockchain[-1]
    del (this_node_transactions[:])
    return jsonify([{
        "index": mined_block.index,
        "timestamp": str(mined_block.timestamp),
        "transactions": mined_block.transactions,
        "proof": mined_block.proof,
        "hash": mined_block.hash
    }])


# 查看区块链
@node.route('/chain', methods=['GET'])
def full_chain():
    response = []
    for block in blockchain:
        block_index = str(block.index)
        block_timestamp = str(block.timestamp)
        block_transactions = str(block.transactions)
        block_proof = str(block.proof)
        block_hash = block.hash
        block = {
            "index": block_index,
            "timestamp": block_timestamp,
            "transactions": block_transactions,
            "proof": block_proof,
            "hash": block_hash
        }
        response.append(block)
    response.append({'len': len(blockchain)})
    render_template('show.html', name=name, age=age, gender='男', friends=friends, dict1=dict1, girl=girlfriend)
    return jsonify(response)

'''

'''

# 发送交易
@node.route('/transaction', methods=['POST'])
def transaction():
    #    if request.method == 'POST':
    # 检查所需的字段是否在POST数据中
    values = request.get_json()
    required = ['id', 'type', 'object','publish_at','object_key','title','summary']
    if not all(k in values for k in required):
        return 'Missing values', 400
    # Then we add the transaction to our listhttp://127.0.0.1:5000/
    this_node_transactions.append(values)
    # Because the transaction was successfully
    # submitted, we log it to our console
    print("New transaction")
    print("type: {}".format(values['type']))
    print("object: {}".format(values['object']))
    print("publish_at: {}".format(values['publish_at']))
    print("object_key: {}".format(values['object_key']))
    print("title: {}".format(values['title']))
    print("summary: {}".format(values['summary']))
    return "Transaction submission successful\n"



if __name__ == '__main__':
    # 生成创世区块添加到链
    blockchain = [create_genesis_block()]
    this_node_transactions = []
    node.run()